import axios, { InternalAxiosRequestConfig, AxiosResponse } from 'axios'
import { ElMessage } from 'element-plus'
import { useAppConfig } from '@/hooks/use-app-config'

const { apiURL, clientId, enableEncrypt } = useAppConfig(import.meta.env, import.meta.env.PROD)

import { stringify } from 'qs'

import {
    decryptBase64,
    decryptWithAes,
    encryptBase64,
    encryptWithAes,
    generateAesKey
} from '@/hooks/utils/encryption/crypto'
import * as encryptUtil from '@/hooks/utils/encryption/jsencrypt'
import { useUserStore } from '@/service/store/modules/user'
import { LanguageEnum } from '@/service/enums/appEnum'
import { router } from '@/router'
import { LoginService } from '@/service/LoginService'

export const globalToken = ref()

const service = axios.create({
    timeout: 15000, // 请求超时时间(毫秒)
    baseURL: import.meta.env.VITE_API_URL
    // baseURL: apiURL
})
type ExtendOptions = {
    /** 响应数据的返回方式。
     * raw: 原始的AxiosResponse，包括headers、status等，不做是否成功请求的检查。
     * body: 返回响应数据的BODY部分（只会根据status检查请求是否成功，忽略对code的判断，这种情况下应由调用方检查请求是否成功）。
     * data: 解构响应的BODY数据，只返回其中的data节点数据（会检查status和code是否为成功状态）。
     */
    responseReturn?: 'body' | 'data' | 'raw'
}
// 请求拦截器
service.interceptors.request.use(
    (config: ExtendOptions & InternalAxiosRequestConfig<any>) => {
        // config.headers.Authorization = globalToken.value ? `Bearer ${globalToken.value}` : null
        const { accessToken } = useUserStore()
        config.headers.Authorization = accessToken
        config.headers.clientId = clientId
        config.headers['Accept-Language'] = LanguageEnum.ZH.replace('-', '_')
        config.headers['Content-Language'] = LanguageEnum.ZH.replace('-', '_')
        /**
         * 格式化get/delete参数
         * 如果包含自定义的paramsSerializer则不走此逻辑
         */
        if (
            ['DELETE', 'GET'].includes(config.method?.toUpperCase() || '') &&
            config.params &&
            !config.paramsSerializer
        ) {
            /**
             * 1. 格式化参数 微服务在传递区间时间选择(后端的params Map类型参数)需要格式化key 否则接收不到
             * 2. 数组参数需要格式化 后端才能正常接收 会变成arr=1&arr=2&arr=3的格式来接收
             */
            config.paramsSerializer = (params) => stringify(params, { arrayFormat: 'repeat' })
        }
        // const { encrypt } = config.encrypt
        // 全局开启请求加密功能 && 该请求开启 && 是post/put请求
        if (enableEncrypt && config.headers.isEncrypt && ['POST', 'PUT'].includes(config.method?.toUpperCase() || '')) {
            const aesKey = generateAesKey()
            config.headers['encrypt-key'] = encryptUtil.encrypt(encryptBase64(aesKey))

            config.data =
                typeof config.data === 'object'
                    ? encryptWithAes(JSON.stringify(config.data), aesKey)
                    : encryptWithAes(config.data, aesKey)
        }
        return config // 返回修改后的配置
    },
    (error) => {
        ElMessage.error(`服务器异常！`) // 显示错误消息
        return Promise.reject(error) // 返回拒绝的 Promise
    }
)

// 响应拦截器
service.interceptors.response.use(
    (response: AxiosResponse) => {
        const encryptKey = (response.headers ?? {})['encrypt-key']
        if (encryptKey) {
            /** RSA私钥解密 拿到解密秘钥的base64 */
            const base64Str = encryptUtil.decrypt(encryptKey)
            /** base64 解码 得到请求头的 AES 秘钥 */
            const aesSecret = decryptBase64(base64Str.toString())
            /** 使用aesKey解密 responseData */
            const decryptData = decryptWithAes(response.data as unknown as string, aesSecret)
            /** 赋值 需要转为对象 */
            response.data = JSON.parse(decryptData)
        }
        const { code } = response.data
        const isRelogin = { show: false }
        if (code === 401) {
            // prettier-ignore
            if (!isRelogin.show) {
                isRelogin.show = true
                ElMessageBox.confirm('登录状态已过期，您可以继续留在该页面，或者重新登录', '系统提示', {
                    confirmButtonText: '重新登录',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    isRelogin.show = false
                    LoginService.logout().then(() => {
                        router.replace({
                            path: '/login',
                            query: {
                                redirect: encodeURIComponent(router.currentRoute.value.fullPath || '/')
                            }
                        })
                    })
                }).catch(() => {
                    isRelogin.show = false
                })
            }
            return Promise.reject('无效的会话，或者会话已过期，请重新登录。')
        }
        return Promise.resolve(response.data)
    },
    (error) => {
        if (axios.isCancel(error)) {
            console.log('repeated request: ' + error.message)
        } else {
            const errorMessage = error.response?.data.msg
            ElMessage.error(errorMessage ? `${errorMessage} ` : `请求超时或服务器异常！`)
        }
        return Promise.reject(error)
    }
)

export default service
